#include "iodialog.h"
#include "ui_iodialog.h"

IODialog::IODialog(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::IODialog)
{
    ui->setupUi(this);
    initChinese();
    initUI();
    initSql();
    initData();
    //loadData();
    //loadIntoUI();
    connectSignalAndSlot();
}

void IODialog::initUI()
{
    //补充占位文字
    ui->pinNameEdit->setPlaceholderText("chinese pin name");
    ui->signalEdit->setPlaceholderText("english pin name");
    //ui->dirPathEdit->setPlaceholderText("input Folder Path");     //这里一般电机文件和工位文件放在同一个文件夹
}

void IODialog::initSql()
{
    dataBase = QSqlDatabase::addDatabase("QSQLITE");
    dataBase.setDatabaseName("pinData.db");

    // 2. 打开数据库
    if (!dataBase.open()) {
        qDebug() << "dataBase connected failed! " << dataBase.lastError().text();
        return;
    }

    qDebug() << "dataBase connected successfully!";

    // 3. 创建表
    QSqlQuery query;
//    QString sql = "CREATE TABLE IF NOT EXISTS datas ("
//                  "row integer, "
//                  "col integer, "
//                  "type integer, "
//                  "pinName TEXT NOT NULL UNIQUE, "
//                  "signal TEXT NOT NULL, "
//                  "functionConnect TEXT NOT NULL,"
//                  "hardwareConnect TEXT NOT NULL,"
//                  "PRIMARY KEY (row, col));";
//    if (!query.exec(sql))
//    {
//        qDebug() << "failed to create table: " << query.lastError().text();
//        dataBase.close();
//        return;
//    }
    //创建IO总数据表
    QString sql = "CREATE TABLE IF NOT EXISTS IOData ("
                  "pinName TEXT NOT NULL PRIMARY KEY, "
                  "signal TEXT NOT NULL); ";
    if (!query.exec(sql))
    {
        qDebug() << "failed to create table: " << query.lastError().text();
        dataBase.close();
        return;
    }
    //创建电机表
    sql = "CREATE TABLE IF NOT EXISTS Motor ("
          "motorName TEXT NOT NULL PRIMARY KEY, "
          "motorNum TEXT NOT NULL); ";
    if (!query.exec(sql))
    {
        qDebug() << "failed to create table: " << query.lastError().text();
        dataBase.close();
        return;
    }
    qDebug() << "dataBase init successfully!";
}

void IODialog::initData()
{
    //初始化hash
    QSqlQuery query;
    if (!query.exec("SELECT * FROM IOData")) {
        qDebug() << "Error executing query: " << query.lastError().text();
        return;
    }

    // 遍历查询结果，读取每一行数据
    while (query.next()) {
        QString pinName = query.value(0).toString();
        QString signal = query.value(1).toString();
        //将数据库中数据放到hash中，方便后续查找
        hash[pinName] = signal;
    }
    //初始化电机hash
    if (!query.exec("SELECT * FROM Motor")) {
        qDebug() << "Error executing query: " << query.lastError().text();
        return;
    }

    // 遍历查询结果，读取每一行数据
    while (query.next()) {
        QString motorName = query.value(0).toString();
        QString motorNum = query.value(1).toString();
        hash[motorName] = motorNum;
    }

    type = INPUTTYPE;
    cardIdx = 0;
    curCardNumIdx = 0;
    curCardNum = 0;
    inputDataSize = 0;
    outputDataSize = 0;
}

void IODialog::connectSignalAndSlot()
{
    connect(ui->confirmBtn,&QPushButton::clicked,this,&IODialog::onInitMotorBtnClicked);
    connect(ui->prevPageBtn,&QPushButton::clicked,this,&IODialog::onPrevPageBtnClicked);
    connect(ui->nextPageBtn,&QPushButton::clicked,this,&IODialog::onNextPageBtnClicked);
    connect(ui->addOrModifyBtn,&QPushButton::clicked,this,&IODialog::onAddOrModifyBtnClicked);
    connect(ui->loadByXlsxBtn,&QPushButton::clicked,this,&IODialog::onLoadXlsxBtnClicked);
    connect(ui->comboBox,&QComboBox::currentTextChanged,this,&IODialog::onComboBoxIndexChanged);
}

//将数据库中上次写入的数据分别写入两个数组中             -- 暂时不使用
void IODialog::loadData()
{
        // 执行查询，获取所有数据
        QSqlQuery query;
        if (!query.exec("SELECT * FROM datas")) {
            qDebug() << "Error executing query: " << query.lastError().text();
            return;
        }

        // 遍历查询结果，读取每一行数据
        while (query.next()) {
            int row  = query.value(0).toInt();
            int col  = query.value(1).toInt();
            Type type  = query.value(2).toInt() == 0 ? INPUTTYPE : OUTPUTTYPE;
            QString pinName = query.value(3).toString();
            QString signal = query.value(4).toString();
            QString functionConnect = query.value(5).toString();
            QString hardConnect = query.value(6).toString();
//            //将数据库中数据放到hash中，方便后续查找
//            hash[pinName] = signal;

            IOData* data = new IOData(pinName,signal,functionConnect,hardConnect);
            //扩容加填入
            if(type == INPUTTYPE)
            {
                int sz = inputData.size();
                if(row >= sz)
                {
                    inputData.resize(row+1);
                    for(int i = sz-1;i<=row;++i)
                    {
                        inputData[i].resize(32);
                    }
                }
                inputData[row][col] = data;
            }
            else if(type == OUTPUTTYPE)
            {
                int sz = outputData.size();
                if(row >= sz)
                {
                    outputData.resize(row+1);
                    for(int i = sz-1;i<=row;++i)
                    {
                        outputData[i].resize(32);
                    }
                }
                outputData[row][col] = data;
            }
        }
}

void IODialog::initChinese()
{
//    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8") );
//    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
}


//添加元素到ListWidget中
void IODialog::addItem(const IOData* data)
{
    //已经超出了卡的数量
    qDebug() << "curCardNumIdx: " << curCardNumIdx << "  curCardNum: " << curCardNum;
//    if(curCardNum == 0)
//    {
//        //这里是切换了界面，但是没有设置卡的数量
//        QMessageBox::warning(NULL,"Warning","please set cardNum");
//        return;
//    }
    //处理功能连接，硬件连接并加载到listWidget中
    IOInfoList* listItemWidget = new IOInfoList(this);
    listItemWidget->setListWidgetData(data);
    QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
    //绑定对应的槽函数，如果该控件修改了，就通知修改对应的数组中的内容
    //connect(listItemWidget,SIGNAL(labelTextChanged(QString,QString)),this,SLOT(onLabelTextChanged(QString,QString)));
    connect(listItemWidget,&IOInfoList::labelTextChanged,this,&IODialog::onLabelTextChanged);
    item->setSizeHint(QSize(listItemWidget->width(),listItemWidget->height()));
    ui->listWidget->setItemWidget(item,listItemWidget);

//    QStandardItem* item = new QStandardItem();
//    item->setData(QVariant::fromValue(listItemWidget));
//    model->appendRow(item);

    ++curCardNumIdx;
    //这里如果添加完该卡的最后一个数据，就直接切换页面
    if(curCardNumIdx == curCardNum)
    {
        curCardNumIdx = 0;
        curCardNum = 0;
        ++cardIdx;
        ui->listWidget->clear();
        ui->cardNumLabel->clear();
    }
}

//获取功能数和硬件连接字符串
void IODialog::getFuncAndHardware(QString &funcStr, QString &hardStr,const QString& pinName)
{
    //根据中文名称来解析出对应的信息
    if(pinName.isEmpty())     funcStr = "9";
    setFunction(pinName,funcStr);
    //硬件连接
    setHardwareConnect(hardStr);
}

//设置引脚的功能
void IODialog::setFunction(const QString &pinName, QString &func)
{
    //qDebug() << "setFunction: pinName: " << pinName;
    QString originStr = "原点";
    if(pinName.contains(originStr))
    {
        func = "3";
        return;
    }
    QString testStr = "测试";
    //qDebug() << "testStr: " << testStr;
    if(pinName.contains(testStr))
    {
        func = "2";
        return;
    }
    QString inputStr = "INPUT";
    QString outputStr = "OUTPUT";
    if(pinName.contains(inputStr) || pinName.contains(outputStr))
    {
        func = "9";
        return;
    }
    QVector<QString> keywords;
    keywords.append("ok");
    keywords.append("ng");
    keywords.append("视觉");
    keywords.append("字符");
    keywords.append("方向");
    keywords.append("打印");
    keywords.append("3D");
    for (int i = 0;i<keywords.size();++i)
    {
        if (pinName.contains(keywords[i],Qt::CaseInsensitive))
        {
            func = "1";
            return;
        }
     }
    func = "0";
}

//设置硬件连接
void IODialog::setHardwareConnect(QString &hardStr)
{
    //ect.0.is.%%.din.%%.in    ect.0.is.4%.dout.%%.out
    char buf[64];
    if(type == INPUTTYPE)
    {
        qDebug() << "setHardwareConnect inputDataSize: " << inputDataSize;
        sprintf(buf,"%d = ect.0.is.%d.din.%02d.in",inputDataSize,41+cardIdx,curCardNumIdx);
    }
    else
    {
        //OUTPUT
        qDebug() << "setHardwareConnect outputDataSize: " << outputDataSize;
        sprintf(buf,"%d = ect.0.is.%d.dout.%02d.out",outputDataSize,41+cardIdx,curCardNumIdx);
    }
    hardStr = buf;
}

//改变页数的时候需要加载新的页面   -- 返回失败说明没有切换
bool IODialog::changePage(QVector<QVector<IOData *> > &datas,int index)
{
    int sz = datas.size();
    //qDebug() << "sz: " << sz <<"  index: " << index;
    if(sz == 0 || index > sz) return false;        //没有数据或者在最后一页的下一页没有数据
    //把界面数据清除
    ui->listWidget->clear();                            //todo：这里的操作可能存在问题，暂时这么做
    if(index == sz)             //跳到最新一页
    {
        curCardNumIdx = curCardNum = 0;
        ui->cardNumLabel->setText(QString::number(curCardNum));           //设置当前卡的数量
        return true;
    }
    //把第index页数据加载到页面
    for(int i = 0;i<datas[index].size();++i)
    {
        IOData* data = datas[index][i];
        IOInfoList* listItemWidget = new IOInfoList(this);
        //为了随时可以修改
        //connect(listItemWidget,SIGNAL(labelTextChanged(QString,QString)),this,SLOT(onLabelTextChanged(QString,QString)));
        connect(listItemWidget,&IOInfoList::labelTextChanged,this,&IODialog::onLabelTextChanged);
        listItemWidget->setListWidgetData(data);
        QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
        item->setSizeHint(QSize(listItemWidget->width(),listItemWidget->height()));
        ui->listWidget->setItemWidget(item,listItemWidget);
    }
    curCardNum = datas[index].size();
    curCardNumIdx = curCardNum;
    ui->cardNumLabel->setText(QString::number(curCardNum));           //设置当前卡的数量
    return true;
}

//修改文件，完成初始化工作      -- number为该初始化的数字
void IODialog::modifyMotorAndStationFile(const QString &filePath,const QString& startStr,int number)
{
    // 打开文件用于读取
    QFile file(filePath);
    if (!file.open(QIODevice::ReadWrite))
    {
        QMessageBox::warning(this, "错误", "无法打开文件: " + file.errorString());
        return;
    }

    QTextStream in(&file);
    QString content;
    bool startModify = false; // 标志变量，用于控制何时开始修改
    while (!in.atEnd())
    {
        QString line = in.readLine();
        // 检查是否是特定的常量字符串
        if (line.trimmed() == startStr)
        {
            startModify = true; // 开始修改
            content += line + "\n"; // 保留该行
            continue;
        }

        if (startModify)
        {
            if (line.contains('['))   // 如果遇到新的 [ 字符，停止修改
            {
                startModify = false;
                content += line + "\n"; // 保留该行
                continue;
            }
            else
            {
                int pos = line.indexOf('=');
                if (pos != -1)
                {
                    QString key = line.left(pos+1);                             // 获取等号左边的英文(包括等号)
                    QString modifiedLine = key + QString::number(number);       // 将数字部分替换为 -1
                    content += modifiedLine + "\n";                             // 将修改后的行添加到内容中
                }
                else
                {
                    content += line + "\n"; // 如果格式不符合，保留原行
                }
            }
        }
        else
        {
            content += line + "\n"; // 如果尚未开始修改，保留原行
        }
    }
    file.close();

    // 打开文件用于写入
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        qDebug() << "can not open file to write: " << filePath;
        return;
    }

    QTextStream out(&file);
    out << content; // 写入修改后的内容
    file.close();

    qDebug() << "finish init file!";
}

//将新增引脚和字母添加到数据库中
void IODialog::insertPinIntoDataBase(const QHash<QString,QString>& hash,
                                     const QString& table,
                                     const QString& chinese,
                                     const QString& letter)
{
    QSqlQuery query;
    foreach (const QString& key , hash.keys())
    {
        QString value =hash.value(key);
        // 首先检查pinName是否存在
        //QString checkQuery = "SELECT COUNT(*) FROM IOData WHERE pinName = :pinName";
        QString checkQuery = "SELECT COUNT(*) FROM " + table + " WHERE " + chinese + " = :chinese";
        query.prepare(checkQuery);
        query.bindValue(":chinese", key);

        if (!query.exec())
        {
            qDebug() << "Error checking pinName existence:" << query.lastError().text();
            return;
        }

        if (query.next())
        {
            int count = query.value(0).toInt();
            if (count > 0)
            {
                // pinName存在，更新signal字段
                //QString updateQuery = "UPDATE IOData SET signal = :signal WHERE pinName = :pinName";
                QString updateQuery = "UPDATE " + table + " SET " +
                        letter + " = :letter WHERE " + chinese + " = :chinese";
                query.prepare(updateQuery);
                query.bindValue(":letter", value);
                query.bindValue(":chinese", key);

                if (!query.exec())
                {
                    qDebug() << "Error updating signal:" << query.lastError().text();
                    return;
                }
            }
            else
            {
                // pinName不存在，插入新的记录
                //QString insertQuery = "INSERT INTO IOData (pinName, signal) VALUES (:pinName, :signal)";
                QString insertQuery = "INSERT INTO " + table + " (" + chinese + ", " + letter +
                        ") VALUES (:chinese, :letter)";
                query.prepare(insertQuery);
                query.bindValue(":letter", value);
                query.bindValue(":chinese", key);

                if (!query.exec())
                {
                    qDebug() << "Error inserting new pinName and signal:" << query.lastError().text();
                    return;
                }
            }
        }
    }
}

//将新增引脚和字母添加到数据库中
//void IODialog::insertPinIntoDataBase()
//{
//    QSqlQuery query;
//    foreach (const QString& key , newPinHash.keys())
//    {
//        QString value =newPinHash.value(key);
//        // 首先检查pinName是否存在
//        QString checkQuery = "SELECT COUNT(*) FROM IOData WHERE pinName = :pinName";
//        query.prepare(checkQuery);
//        query.bindValue(":pinName", key);

//        if (!query.exec())
//        {
//            qDebug() << "Error checking pinName existence:" << query.lastError().text();
//            return;
//        }

//        if (query.next())
//        {
//            int count = query.value(0).toInt();
//            if (count > 0)
//            {
//                // pinName存在，更新signal字段
//                QString updateQuery = "UPDATE IOData SET signal = :signal WHERE pinName = :pinName";
//                query.prepare(updateQuery);
//                query.bindValue(":signal", value);
//                query.bindValue(":pinName", key);

//                if (!query.exec())
//                {
//                    qDebug() << "Error updating signal:" << query.lastError().text();
//                    return;
//                }
//            }
//            else
//            {
//                // pinName不存在，插入新的记录
//                QString insertQuery = "INSERT INTO IOData (pinName, signal) VALUES (:pinName, :signal)";
//                query.prepare(insertQuery);
//                query.bindValue(":signal", value);
//                query.bindValue(":pinName", key);

//                if (!query.exec())
//                {
//                    qDebug() << "Error inserting new pinName and signal:" << query.lastError().text();
//                    return;
//                }
//            }
//        }
//    }
//}

//将两个数组中的信息写入到文件中
void IODialog::loadDataIntoFile()
{
    //通过多个String把每一部分的内容存储起来，最后拼接到一起写入数据库中
    const QString filePath = dirPath + QDir::separator() + "newio.ini";
    QFile file(filePath);
    if (!file.open(QIODevice::ReadWrite))
    {
        QMessageBox::warning(this, "错误", "无法打开文件: " + file.errorString());
        return;
    }

    QTextStream out(&file);

    // 收集所有内容
    QVector<QString> inPutHardwareConnects,outPutHardwareConnects;
    int inPutNum = 0,outPutNum = 0;

    foreach (const QVector<IOData*>& row , inputData)
    {
        foreach (const IOData* ioData , row)
        {
            inPutHardwareConnects.append(ioData->_hardwareConnect);
            ++inPutNum;
        }
    }

    foreach (const QVector<IOData*>& row , outputData)
    {
        foreach (const IOData* ioData , row)
        {
            outPutHardwareConnects.append(ioData->_hardwareConnect);
            ++outPutNum;
        }
    }
    //写入FLAG
    out << "[FLAG]\n";
    out << "IOCONTROL=1\n";
    //写入MAX
    out << "[MAX]\n";
    out << "IN=" << QString::number(inPutNum) << "\n";
    out << "OUT=" + QString::number(outPutNum) << "\n";
    out << "\n";

    //写入输入硬件连接
    out << "[IN]\n";
    foreach(const QString& data , inPutHardwareConnects)
    {
        out << data << "\n";
    }
    out << "\n";
    //写入输出硬件连接
    out << "[OUT]\n";
    foreach(const QString& data , outPutHardwareConnects)
    {
        out << data << "\n";
    }
    out << "\n";
    //写入每一个IO点的数据
    int num = 0;        //用来记录节点数量
    foreach (const QVector<IOData*>& row , inputData)
    {
        foreach (const IOData* ioData , row)
        {
            out << "[INPUT_" + ioData->_signal + "]\n";
            out << "NAME = " + ioData->_pinName + "\n";
            out << "NUM = " + QString::number(num) + "\n";
            out << "POL = 0" << "\n";
            out << "DEFAULT = 0" << "\n";
            out << "SIGNAL_NAME = " + ioData->_signal + "\n";
            out << "PIN1 = " + ioData->_functionConnect + "\n\n";
            ++num;
        }
    }
    num = 0;
    foreach (const QVector<IOData*>& row , outputData)
    {
        foreach (const IOData* ioData , row)
        {
            out << "[OUTPUT_" + ioData->_signal + "]\n";
            out << "NAME = " + ioData->_pinName + "\n";
            out << "NUM = " + QString::number(num) + "\n";
            out << "POL = 0" << "\n";
            out << "DEFAULT = 0" << "\n";
            out << "SIGNAL_NAME = " + ioData->_signal + "\n";
            out << "PIN1 = " + ioData->_functionConnect + "\n\n";
            ++num;
        }
    }

    file.close();
}

//对输入输出数组进行扩容
void IODialog::resizeVector(QVector<QVector<IOData *> > &data)      //该函数在自动化输入的时候再使用
{
    if(cardIdx >= data.size())      //新的一页
    {
        data.resize(cardIdx+1);
    }
    //扩容当前列
    //data[cardIdx].resize(curCardNum);        //todo：如果是缩容，那这里会存在内存泄露
}

//加载数据到数组中并展示到页面
void IODialog::loadDataintoVectorAndShow(const QString &pinName, const QString &signal)
{
    QString funcStr ,hardwareStr;
    getFuncAndHardware(funcStr,hardwareStr,pinName);
    IOData* data = new IOData(pinName,funcStr,signal,hardwareStr);
    //检测新界面是否读取有卡数
    if(curCardNum == 0)
    {
        QMessageBox::warning(NULL,"Warning","please set cardNum");
        return;
    }
    if(type == INPUTTYPE)
    {
        inputData[cardIdx][curCardNumIdx] = data;
        ++inputDataSize;
    }
    else
    {
        outputData[cardIdx][curCardNumIdx] = data;
        ++outputDataSize;
    }
    addItem(data);
}

void IODialog::modifyVectorByIndex(QVector<QVector<IOData *> > &data, int row, int col, const QString& label)
{
    int index = label[0].digitValue();
    QString modifyText = label.mid(1);
    switch(index)
    {
    case 0:
        data[row][col]->_pinName = modifyText;
        break;
    case 1:
        data[row][col]->_signal = modifyText;
        break;
    case 2:
        data[row][col]->_functionConnect = modifyText;
        break;
    default:
        //这里硬件连接不允许修改
        qDebug() << "can not modify By input";
        break;
    }
}

void IODialog::readXlsxDataintoVector()
{
    // 打开 Excel 文件
    QString excelPath = dirPath + QDir::separator() + "NT.xlsx";
    if (!QFile::exists(excelPath))
    {
        QMessageBox::critical(nullptr, "错误", "文件不存在，请检查路径是否正确！");
        return;
    }
    QXlsx::Document xlsx(excelPath);
    QStringList sheetNames = xlsx.sheetNames();

    // 定义规则：工作表名称以“卡”结尾
    QRegularExpression pattern("卡$"); // 正则表达式，$ 表示字符串结尾

    int totalCardNum = 0;   //统计当前卡的总的卡数
    // 遍历所有工作表
    foreach (const QString &sheetName, sheetNames)
    {
        // 切换到当前工作表
        xlsx.selectSheet(sheetName);

        //特殊处理一下电机配置的写入
        if(sheetName == "排位图")
        {
            handleMotorConfig(xlsx);
            continue;
        }
        // 检查工作表名称是否以“卡”结尾
        if (pattern.match(sheetName).hasMatch())
        {
            qDebug() << "Reading sheet:" << sheetName;

            int totalRows = xlsx.dimension().lastRow();         // 获取总行数
            int totalColumns = xlsx.dimension().lastColumn();   // 获取总列数

            int currentRow = 1;     // 从第一行开始
            while (currentRow <= totalRows)
            {
                // 1. 读取第一行，获取卡数
                int cardCount = 0;
                for(int col = 1; col <= totalColumns; ++col)
                {
                    QString cellValue = xlsx.read(currentRow, col).toString();
                    if(!cellValue.isEmpty())
                    {
                        QString str = xlsx.read(currentRow, col).toString();
                        QString lastTwoDigits = str.right(2);  // 直接取最后两位
                        cardCount = lastTwoDigits.toInt();
                        break;
                    }
                }
                qDebug() << "Card Count:" << cardCount;

                // 2. 从第二行开始，找到“引脚定义”这一行
                QString pinDefinitionText = "引脚定义";
                int pinDefinitionRow = -1;
                int pinDefinitionCol = -1; // 用于记录“引脚定义”所在的列
                for (int row = currentRow + 1; row <= totalRows; ++row)
                {
                    for (int col = 1; col <= totalColumns; ++col)
                    {
                        QString cellValue = xlsx.read(row, col).toString();
                        if (cellValue == pinDefinitionText)
                        {
                            pinDefinitionRow = row;
                            pinDefinitionCol = col;
                            break;
                        }
                    }
                    if (pinDefinitionRow != -1)
                    {
                        break;
                    }
                }

                if (pinDefinitionRow == -1)
                {
                    qDebug() << "No '引脚定义' found. Stopping.";
                    break;
                }

                qDebug() << "Pin Definition Row:" << pinDefinitionRow
                         << "Pin Definition Col:" << pinDefinitionCol;

                // 3. 从“引脚定义”行的下一行开始，读取卡数的两倍行数，一半是输入，一半是输出
                int rowsToRead = cardCount * 2;
                //输入
                int row = pinDefinitionRow + 1;
                for (; row < pinDefinitionRow + cardCount + 1 && row <= totalRows; ++row)
                {
                    QString cellValue = xlsx.read(row, pinDefinitionCol).toString();  //获取到名称
                    IOData* data = getDataBypinName(cellValue,INPUTTYPE);
                    if(totalCardNum >= inputData.size())    //扩容
                    {
                        inputData.resize(totalCardNum + 1);
                    }
                    inputData[totalCardNum].push_back(data);
                    ++curCardNumIdx;            //维护无效输入输出的正确显示
                    //qDebug() << "Row" << row << "Col" << pinDefinitionCol << ":" << cellValue;
                }
                //输出
                curCardNumIdx = 0;
                for (; row < pinDefinitionRow + rowsToRead + 1 && row <= totalRows; ++row)
                {
                    //qDebug() << "outputDataSize: " << outputDataSize;
                    QString cellValue = xlsx.read(row, pinDefinitionCol).toString();
                    IOData* data = getDataBypinName(cellValue,OUTPUTTYPE);
                    if(totalCardNum >= outputData.size())    //扩容
                    {
                        outputData.resize(totalCardNum + 1);
                    }
                    outputData[totalCardNum].push_back(data);
                    ++curCardNumIdx;
                    //qDebug() << "Row" << row << "Col" << pinDefinitionCol << ":" << cellValue;
                }
                // 4. 更新当前行，跳过已读取的行
                currentRow = pinDefinitionRow + rowsToRead + 1;
                // 5. 更新当前的总的卡的数量
                ++totalCardNum;
                ++cardIdx;
            }
        }
    }
}

IOData *IODialog::getDataBypinName(QString &pinName,Type t)
{
    //构建IOData数据
    //1.在hash中找对应的信号
    type = t;
    QString singnal;
    if(hash.contains(pinName))
    {
        singnal = hash[pinName];
    }
    else
    {
        singnal = "none";           //找不到
    }
    //2.对pinName为"",以及信号为none的情况做处理
    if(pinName == "")
    {
        char buf[64];
        if(type == INPUTTYPE) sprintf(buf,"INPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
        else sprintf(buf,"OUTPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
        pinName = buf;
        singnal =buf;
    }
    else if(singnal == "none" || singnal == "")
    {
        char buf[64];
        if(type == INPUTTYPE) sprintf(buf,"INPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
        else sprintf(buf,"OUTPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
        singnal =buf;
    }
    qDebug() << "pinName: " << pinName << " signal: " << singnal;
    //3.构建对应的功能连接和硬连接
    QString funcStr ,hardwareStr;
    getFuncAndHardware(funcStr,hardwareStr,pinName);
    IOData* data = new IOData(pinName,funcStr,singnal,hardwareStr);
    if(type == INPUTTYPE) ++inputDataSize;
    else ++outputDataSize;
    //4.构建data数据并返回
    return data;
}

void IODialog::testReadpinNameFromDatabase()
{
    //读取Excel文件，将全部对应的数据读取到数据库中
    // 打开 Excel 文件
    QString excelPath = dirPath + QDir::separator() + "pinName.xlsx";
    if (!QFile::exists(excelPath))      //像这种添加的文件没有就返回
    {
        return;
    }
    QXlsx::Document xlsx(excelPath);
    // 遍历工作表2
    xlsx.selectSheet("Sheet2");

    int totalRows = xlsx.dimension().lastRow();         // 获取总行数
    int totalColumns = xlsx.dimension().lastColumn();   // 获取总列数

    int currentCol = 1;     // 从第一列开始
    // 从第二行开始，找到“中文名称”这一列
    QString pinDefinitionText = "中文名称";
    int pinDefinitionRow = 2;
    int pinDefinitionCol = -1;
    for (int col = currentCol; col <= totalColumns; ++col)
    {
        QString cellValue = xlsx.read(pinDefinitionRow, col).toString();
        if (cellValue == pinDefinitionText)
        {
            pinDefinitionCol = col;
        }
        if(pinDefinitionCol != -1)
        {
            //开始处理数据，将行列中的数据放入到数据库中，这里只需要把数据写入到newHash中即可
            for(int row = pinDefinitionRow + 1;row <= totalRows;++row)
            {
                QString pinName = xlsx.read(row, pinDefinitionCol).toString();
                if(pinName.isEmpty()) break;
                QString signal = xlsx.read(row, pinDefinitionCol + 1).toString();
                newPinHash[pinName] = signal;       //新增引脚
            }
            //还有输出列要处理
            pinDefinitionCol = -1;
            ++col;
        }
    }
}

void IODialog::loadMotorDataintoDatabase()
{
    //读取Excel文件，将全部对应的电机数据读取到数据库中
    // 打开 Excel 文件
    QString excelPath = dirPath + QDir::separator() + "motor_num.xlsx";
    if (!QFile::exists(excelPath))      //像这种添加的文件没有就返回
    {
        return;
    }
    QXlsx::Document xlsx(excelPath);
    // 遍历工作表1
    xlsx.selectSheet("Sheet1");
    int totalRows = xlsx.dimension().lastRow();         // 获取总行数
    int col = 1;        //读取第一和第二行
    // 从第2行开始读取全部的数据
    for(int row = 2;row <= totalRows;++row)
    {
        QString motor = xlsx.read(row, col).toString();
        QString motorName = xlsx.read(row, col + 1).toString();
        QString res;
        //截取=之前的字符
        int equalPos = motor.indexOf('='); // 找到'='的位置
        if (equalPos != -1) // 如果找到了'='
        {
            res = motor.left(equalPos); // 截取'='之前的部分
        }
        else
        {
            res = motor;
        }
        //放入到motorHash中
        motorHash[motorName] = res;
    }
    for (auto& key : motorHash.keys())
    {
         qDebug() << "motorName:" << key << "motorNum: " << motorHash[key];
    }
    //将数据加载到数据库
    insertPinIntoDataBase(motorHash,"Motor","motorName","motorNum");
}

void IODialog::handleMotorConfig(QXlsx::Document &xlsx)
{
    //读取排位图中的电机编号以及名称，写入到对应的电机文件中
    int totalRows = xlsx.dimension().lastRow();         // 获取总行数
    int totalCols = xlsx.dimension().lastColumn();      // 获取总列数
    int posRow = -1;
    int posCol = -1;
    for(int row = 1;row <= totalRows;++row)
    {
        for (int col = 1; col <= totalCols; ++col)
        {
            QString str = xlsx.read(row, col).toString();
            if(str == "驱动排位")
            {
                posRow = row;
                posCol = col;
                break;
            }
        }
        if(posRow != -1) break;
    }
    if(posRow == -1) return;        //没有找到驱动排位
    QHash<QString,QString> res;     //收集结果，存放motorNum和数字的对应关系
    //读取全部的配置
    for(int row = posRow+1;row <= totalRows;++row)
    {
        QString idx = xlsx.read(row, posCol).toString();
        if(idx == "通讯网线") break;
        QString motorName = xlsx.read(row, posCol+1).toString();
        QString motorNum;
        if(motorHash.contains(motorName))
        {
            motorNum = motorHash[motorName];
            res[motorNum] = idx;
        }
    }
//    for(auto& key : res.keys())
//    {
//        qDebug() << "res: key: " << key << "val: " << res[key];
//    }
    //将结果集写入到文件中
    writeMotorIntoFile(res);
}

void IODialog::writeMotorIntoFile(const QHash<QString, QString> &hashTable)
{
    const QString filePath = dirPath + QDir::separator() + "motor_num.ini";
    QFile inputFile(filePath);
    if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "无法打开文件：" << filePath;
        return;
    }
    //读取文件并配置
    QTextStream in(&inputFile);
    QStringList lines;
    while (!in.atEnd())
    {
        QString line = in.readLine();
        int equalPos = line.indexOf('='); // 找到等号的位置

        if (equalPos != -1)
        {
            QString key = line.left(equalPos).trimmed(); // 获取等号左边的内容并去除空格
            if (hashTable.contains(key)) // 在哈希表中查找
            {
                QString newValue = hashTable.value(key); // 获取哈希表中的值
                line = key + "=" + newValue; // 替换为新值
            }
        }
        lines.append(line); // 将处理后的行存储到列表中
    }
    inputFile.close();
    // 打开文件进行写入
    if (!inputFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        qDebug() << "无法打开文件进行写入：" << filePath;
        return;
    }

    QTextStream out(&inputFile);
    foreach (const QString &line, lines)
    {
        out << line << "\n"; // 写入处理后的行
    }
    inputFile.close();
}


//void IODialog::onConfirmBtnClicked()
//{
//    //拿到输入框中的中文去hash中查找
//    QString text = ui->chineseNameEdit->text();
//    if(hash.contains(text))
//    {
//        ui->resultLabel->setText(hash[text]);
//    }
//    else
//    {
//        ui->resultLabel->setText("none");           //找不到
//    }
//}


//void IODialog::onWriteBtnClicked()
//{
//    //根据前面输入的中文名和搜索结果来填写到ListWidget中
//    //如果已经满了，需要修改卡数才能继续添加
//    if(curCardNumIdx  == curCardNum)
//    {
//        QMessageBox::warning(NULL,"Warning","curCard is fulled");
//        return;
//    }
//    QString pinName = ui->chineseNameEdit->text();
//    QString pinEnglishName = ui->resultLabel->text();
//    ui->chineseNameEdit->clear();
//    ui->resultLabel->clear();
//    //将内容添加到ListView中
//    //对pinName为"",以及信号为none的情况做处理
//    if(pinName == "")
//    {
//        char buf[64];
//        if(type == INPUT) sprintf(buf,"INPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
//        else sprintf(buf,"OUTPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
//        pinName = buf;
//        pinEnglishName =buf;
//    }
//    else if(pinEnglishName == "none" || pinEnglishName == "")
//    {
//        char buf[64];
//        if(type == INPUT) sprintf(buf,"INPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
//        else sprintf(buf,"OUTPUT_%d_%02d",cardIdx+1,curCardNumIdx+1);
//        pinEnglishName =buf;
//    }
//    qDebug() << "pinName: " << pinName << " signal: " << pinEnglishName;
//    //收集全部的数据写入到数组中，然后再写入到界面上
//    loadDataintoVectorAndShow(pinName,pinEnglishName);
//}

void IODialog::onAddOrModifyBtnClicked()
{
    //查找hash中的数据，如果有就更新，如果没有就往新的hash中添加
    QString pinName = ui->pinNameEdit->text();
    QString pinEnglishName = ui->signalEdit->text();
    ui->pinNameEdit->clear();
    ui->signalEdit->clear();
    newPinHash[pinName] = pinEnglishName;       //新增或者修改是在数据库中进行操作
//    if(hash.contains(pinName))
//    {
//        hash[pinName] = pinEnglishName;             //修改
//    }
//    else
//    {
//        //新增
//        newPinHash[pinName] = pinEnglishName;
//    }
    //将内容添加到ListWidget中
    //loadDataintoVectorAndShow(pinName,pinEnglishName);         //使用excel读取方式不使用
}

void IODialog::onWriteFileBtnClicked()                  //不使用了，采用其他方式
{
    //遍历ListWidget中的内容，将内容写入vector中即可，后续在关闭程序的时候再写入文件中
    int count = ui->listWidget->count();
    if(count < curCardNum)
    {
        QMessageBox::warning(NULL,"Warning","inputCount less than cardCount,please continue typing");
        return;
    }
    for(int i = 0;i<count;++i)
    {
        QListWidgetItem* item = ui->listWidget->item(i);
        QWidget* widget = ui->listWidget->itemWidget(item);         //todo：需要删除该widget防止内存泄露
        if(widget)
        {
            IOInfoList* listWidgetCast = qobject_cast<IOInfoList*>(widget);
            if(listWidgetCast)
            {
                QString pinName = listWidgetCast->getChineseNameLabel();
                QString functionConnect = listWidgetCast->getFuncLabel();
                QString signal = listWidgetCast->getSignalLabel();
                QString hardConnect = listWidgetCast->getHardwareConnectLabel();
                IOData* data = new IOData(pinName,functionConnect,signal,hardConnect);
                if(type == INPUTTYPE) inputData[cardIdx][i] = data;
                else
                {
                    outputData[cardIdx][i] = data;
                }
            }
        }
    }
    //写入之后自动跳转到下一页，加载下一页的数据
    ++cardIdx;
    ui->listWidget->clear();    //清除当前页面数据          todo:这里只是清空了界面数据，但是自定义数据不会释放
}

//初始化电机以及工位
void IODialog::onInitMotorBtnClicked()
{
    //读取对应的文件，将电机数量置为-1，工位开启置为0，工位数置-1
    QString folderPath = QFileDialog::getExistingDirectory(
        this,
        tr("选择文件夹"),
        QDir::homePath(),  // 默认从用户主目录开始
        QFileDialog::ShowDirsOnly
    );
    if(folderPath.isEmpty()) return;
    dirPath = folderPath;
    //初始化电机数量
    QString motorFilePath = folderPath + QDir::separator() + "motor_num.ini";
    modifyMotorAndStationFile(motorFilePath,"[MOTOR_NUM]",-1);
    //初始化工位
    QString stationPath = folderPath + QDir::separator() + "NortechSystemData.ini";
    modifyMotorAndStationFile(stationPath,"[GONGWEIKAIQI]",0);
    modifyMotorAndStationFile(stationPath,"[GONGWEISHUNXU]",-1);
    //将数据读取到数据库中
    testReadpinNameFromDatabase();
    //将电机的配置加载进来（如果有这个文件）
    loadMotorDataintoDatabase();
}

//上一页按钮点击
void IODialog::onPrevPageBtnClicked()
{
    if(cardIdx == 0) return;
    --cardIdx;
    qDebug() << "cardIdx: " << cardIdx;
    if(type == INPUTTYPE)
    {
        changePage(inputData,cardIdx);
    }
    else
        changePage(outputData,cardIdx);
}

//下一页按钮点击
void IODialog::onNextPageBtnClicked()
{
    //如果当前页没有将数据写入数组中，不允许切换到下一页，否则切换回来的时候会越界访问
    if(type == INPUTTYPE)
    {
        if(curCardNumIdx < curCardNum)
        {
            //这里没有写完该页，不允许切页
            QMessageBox::warning(NULL,"Warning","Please enter the full content and then jump to next page");
            return;
        }
        if(curCardNum != 0)     ++cardIdx;
        changePage(inputData,cardIdx);
    }
    else
    {
        if(curCardNumIdx < curCardNum)
        {
            //这里没有写完该页，不允许切页
            QMessageBox::warning(NULL,"Warning","Please enter the full content and then jump to next page");
            return;
        }
        if(curCardNum != 0)     ++cardIdx;
        changePage(outputData,cardIdx);
    }
}

//void IODialog::onModifyCardNumBtnClicked()
//{
//    QString text = ui->cardNumLabel->text();
//    curCardNum = text.toInt();
//    //给当前行数组进行空间调整
//    if(type == INPUT)
//    {
//        resizeVector(inputData);
//    }
//    else
//    {
//        resizeVector(outputData);
//    }
//}

//自动化读取excel中的数据
void IODialog::onLoadXlsxBtnClicked()
{
    //1.读取文件内容中的引脚定义，然后把对应的内容加载到输入输出数组中
    readXlsxDataintoVector();
    //2.读取数组内容，将对应的内容配置完成并加载到界面中,这里加载第一行输入数组的内容即可
    //2.1读取数组的大小写到当前的卡数中
    if(inputData.size()== 0) return;
    ui->cardNumLabel->setText(QString::number(inputData.size()));
    //2.2读取输入数组的内容展现在界面中
    for(int j = 0;j<inputData[0].size();++j)
    {
        addItem(inputData[0][j]);
    }
    //3.设置3个记录的参数
    curCardNum = inputData[0].size();
    cardIdx = 0;        //当前在第一卡
    ui->cardNumLabel->setText(QString::number(curCardNum));
    type = INPUTTYPE;
}

//类型改变之后触发
void IODialog::onComboBoxIndexChanged()
{
    //改变类型，加载数据
    type = type == INPUTTYPE ? OUTPUTTYPE : INPUTTYPE;
    cardIdx = 0;
    curCardNumIdx = 0;
    ui->listWidget->clear();    //todo: 需要去清空自定义数据
    if(type == INPUTTYPE)
        changePage(inputData,0);
    else
        changePage(outputData,0);
}

//修改数组中的数据
void IODialog::onLabelTextChanged(const QString &label, const QString &hardwareStr)
{
    //1.解析对应的行列
    // 使用 split 方法按 '.' 分割字符串
    QStringList parts = hardwareStr.split('.');
    int row = 0,col = 0;
    // 检查分割后的部分是否足够
    if (parts.size() >= 6)
    {
        QString number1 = parts[3];  // 获取第 4 个部分（索引为 3）
        QString number2 = parts[5];  // 获取第 6 个部分（索引为 5）
        row = number1.toInt() - 41;
        col = number2.toInt();
        qDebug() << "Number 1:" << number1;
        qDebug() << "Number 2:" << number2;
    }
    else
    {
        qDebug() << "Input string does not have enough parts.";
    }
    //2.修改数组中的内容
    if(type == INPUTTYPE) modifyVectorByIndex(inputData,row,col,label);
    else modifyVectorByIndex(outputData,row,col,label);
}

IODialog::~IODialog()
{
    insertPinIntoDataBase(newPinHash,"IOData","pinName","signal");
    loadDataIntoFile();
    dataBase.close();
    delete ui;
}

